feat: expose apple intelligence availability reason - #225
Open
jaimebg wants to merge 1 commit into
Open
Conversation
isAvailable() collapsed SystemLanguageModel.Availability into a boolean, so apps could not tell an ineligible device apart from Apple Intelligence simply being switched off, and had no way to point the user at Settings. Add getAvailability() alongside it, returning the reason Apple already exposes via .unavailable(reason). MODEL_UNAVAILABLE errors now carry the same detail instead of a single generic message. isAvailable() keeps its boolean contract and is now derived from getAvailability().
|
@jaimebg is attempting to deploy a commit to the Callstack Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
isAvailable()collapses Apple'sSystemLanguageModel.Availabilityinto a plain boolean, so the reason Apple Intelligence is unavailable is lost at the bridge. Apps can't tell "this device can't run it" apart from "the user hasn't switched Apple Intelligence on" — which is a real UX loss, because the second one is fixable by the user and we currently can't tell them so. The model still downloading (modelNotReady) is likewise indistinguishable from a permanent failure.Apple exposes the reason via
.unavailable(reason); this PR stops throwing it away.Changes
New
getAvailability()on the provider (apple.getAvailability()), onAppleFoundationModels, and on the TurboModule spec. Returns a string union:availabledeviceNotEligibleappleIntelligenceNotEnabledmodelNotReadyunsupportedOSunknownunsupportedOSmatches the vocabulary already used byAppleLLMErrorCodes.UnsupportedOS;unknownkeeps the wrapper forward-compatible if Apple adds reasons.MODEL_UNAVAILABLEerrors now carry the same detail, e.g. "Apple Intelligence model is not available: Apple Intelligence is not enabled in Settings" instead of one generic message, acrossgenerateText,generateStreamandcountTokens. The error code is unchanged.AppleAvailabilitytype exported from the package entrypoint.Docs: new "Availability Status" section in
apple/generating.md, plus pointers fromrunning-on-simulator.mdand the agent skill reference.Not a breaking change
isAvailable(): booleankeeps its exact contract and stays in the native spec — it's now derived fromgetAvailability(), so the two can't drift. Every existing snippet in the docs and the example app keeps working;getAvailability()is purely additive for callers who want the reason.Test plan
I don't have an Apple Intelligence-capable device to hand, so this hasn't been exercised on-device — the reason-specific branches in particular would benefit from a maintainer sanity check. What I did verify:
bun run lintandbun run typecheck(whole monorepo) pass.bun run prepareinpackages/apple-llmbuilds; emitted.d.tsexposesgetAvailability(): AppleAvailabilityand the exported type.AppleAvailability.swift,AppleLLMError.swiftandAppleLLMImpl.swiftpassswiftc -typecheckagainst the real iOS 26 SDK — including theswitchoverSystemLanguageModel.default.availability, which is exhaustive without needing@unknown default.StringLiteralUnionTypeAnnotationand generates- (NSString *)getAvailability;with aStringKindsync host function, which is whatAppleLLM.mmimplements.Suggested on-device checks: toggle Apple Intelligence off in Settings → expect
appleIntelligenceNotEnabled; on an ineligible device →deviceNotEligible; right after enabling, before the download finishes →modelNotReady.Possible follow-up
The example app's
SetupAdapter.isAvailable()still maps to the 3-state'yes' | 'no' | 'availableForDownload', so it doesn't surface the new reason in the UI. I left it alone to keep this PR to one logical change, but happy to add it here if you'd prefer the demo to show it off.Notes